package pkg

import (
	"context"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/go-pay/gopay"
	"github.com/go-pay/gopay/alipay"
	"github.com/go-pay/xlog"
	"github.com/spf13/viper"
	"net/http"
)

type PayData struct {
	OutTradeNo  string `json:"outTradeNo"`
	TotalAmount string `json:"totalAmount"`
	Subject     string `json:"subject"`
	ReturnUrl   string `json:"returnUrl"`
	NotifyUrl   string `json:"notifyUrl"`
}

func NewPayData() *PayData {
	return &PayData{}
}
func (p *PayData) Pay(s *PayData) (string, error) {
	client, err := alipay.NewClient(viper.GetString("alipay_app_id"), viper.GetString("private_key"), false)
	if err != nil {
		return "", fmt.Errorf("支付宝错误信息:::%v", err)
	}
	client.DebugSwitch = gopay.DebugOn // 打开Debug开关，输出日志，默认关闭
	err = client.SetCertSnByContent(
		[]byte(viper.GetString("app_public_cert")),
		[]byte(viper.GetString("alipay_root_cert")),
		[]byte(viper.GetString("alipay_public_cert")),
	)
	if err != nil {
		return "", fmt.Errorf("支付宝证书错误信息:::%v", err)
	}
	bm := make(gopay.BodyMap) // 初始化 BodyMap
	bm.Set("out_trade_no", s.OutTradeNo).
		Set("total_amount", s.TotalAmount).
		Set("subject", s.Subject).
		Set("product_code", "FAST_INSTANT_TRADE_PAY").
		Set("return_url", s.ReturnUrl).
		Set("notify_url", s.NotifyUrl)
	return client.TradePagePay(context.Background(), bm)
}

// gin框架验签
func Verification(c *gin.Context) (gopay.BodyMap, error) {
	fmt.Println("收到回调")
	// 解析异步通知的参数
	notifyReq, err := alipay.ParseNotifyToBodyMap(c.Request) // c.Request 是 gin 框架的写法
	if err != nil {
		xlog.Error(err)
		return nil, err
	}
	// 支付宝异步通知验签（公钥证书模式）
	ok, err := alipay.VerifySignWithCert([]byte(viper.GetString("alipay_public_cert")), notifyReq)
	if err != nil {
		xlog.Error(err)
		return nil, err
	}
	if !ok {
		fmt.Println("签名效验失败：：", ok)
		return nil, err
	}
	// ====异步通知，返回支付宝平台的信息====
	// 文档：https://opendocs.alipay.com/open/203/105286
	// 程序执行完后必须打印输出“success”（不包含引号）。如果商户反馈给支付宝的字符不是success这7个字符，支付宝服务器会不断重发通知，直到超过24小时22分钟。一般情况下，25小时以内完成8次通知（通知的间隔频率一般是：4m,10m,10m,1h,2h,6h,15h）
	fmt.Println("验签结果", ok)
	// 此写法是 gin 框架返回支付宝的写法
	c.String(http.StatusOK, "%s", "success")
	return notifyReq, nil
}
